package com.myl.api.interceptor;

import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.config.SaSignConfig;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.SaSignException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.fun.SaParamFunction;
import cn.dev33.satoken.sign.SaSignTemplate;
import cn.dev33.satoken.sign.SaSignUtil;
import cn.dev33.satoken.strategy.SaStrategy;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.TreeMap;

/**
 * SaInterceptor
 * author: myl <ixiaomu@qq.com>
 * tips:
 */
@Slf4j
public class SaInterceptor implements HandlerInterceptor {

    /**
     * 是否打开注解鉴权
     */
    public boolean isAnnotation = true;

    /**
     * 认证函数：每次请求执行
     * <p> 参数：路由处理函数指针
     */
    public SaParamFunction<Object> auth = handler -> {
        // TODO
        // API 接口参数签名 验证
//        SaSignUtil.checkRequest(SaHolder.getRequest());
    };

    /**
     * 创建一个 Sa-Token 综合拦截器，默认带有注解鉴权能力
     */
    public SaInterceptor() {
    }

    /**
     * 创建一个 Sa-Token 综合拦截器，默认带有注解鉴权能力
     * @param auth 认证函数，每次请求执行
     */
    public SaInterceptor(SaParamFunction<Object> auth) {
        this.auth = auth;
    }

    /**
     * 设置是否打开注解鉴权
     * @param isAnnotation /
     * @return 对象自身
     */
    public SaInterceptor isAnnotation(boolean isAnnotation) {
        this.isAnnotation = isAnnotation;
        return this;
    }

    /**
     * 写入[认证函数]: 每次请求执行
     * @param auth /
     * @return 对象自身
     */
    public SaInterceptor setAuth(SaParamFunction<Object> auth) {
        this.auth = auth;
        return this;
    }


    // ----------------- 验证方法 -----------------

    /**
     * 每次请求之前触发的方法
     */
    @Override
    @SuppressWarnings("all")
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        try {
            // 这里必须确保 handler 是 HandlerMethod 类型时，才能进行注解鉴权
            if(isAnnotation && handler instanceof HandlerMethod) {

                // 获取此请求对应的 Method 处理函数
                Method method = ((HandlerMethod) handler).getMethod();

                // 如果此 Method 或其所属 Class 标注了 @SaIgnore，则忽略掉鉴权
                if(SaStrategy.instance.isAnnotationPresent.apply(method, SaIgnore.class)) {
                    // 注意这里直接就退出整个鉴权了，最底部的 auth.run() 路由拦截鉴权也被跳出了
                    return true;
                }

                // 注解校验
                SaStrategy.instance.checkMethodAnnotation.accept(method);
            }

            // Auth 校验
            auth.run(handler);

        } catch (StopMatchException e) {
            // StopMatchException 异常代表：停止匹配，进入Controller

        } catch (BackResultException e) {
            // BackResultException 异常代表：停止匹配，向前端输出结果
            // 		请注意此处默认 Content-Type 为 text/plain，如果需要返回 JSON 信息，需要在 back 前自行设置 Content-Type 为 application/json
            // 		例如：SaHolder.getResponse().setHeader("Content-Type", "application/json;charset=UTF-8");
            if(response.getContentType() == null) {
                response.setContentType("text/plain; charset=utf-8");
            }
            response.getWriter().print(e.getMessage());
            return false;
        }

        // 通过验证
        return true;
    }
}
